#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <glf/core/thread.h>

#include <deque>

int signo =SIGIO;

namespace glf {
	
struct FileStreamImpl::Impl : public FileStreamImplBase {
	FILE* mHandle;

	Impl(FileStreamImpl& fileStream) :
		FileStreamImplBase(fileStream),
		mHandle(0)
	{
		//dont use mFileStream here
	}

	bool Open(const char* filename, openflag flag) {
		bool ensureCreated	= TestFlag(flag, create);
		bool openAtEnd		= TestFlag(flag, atend);
		bool truncAtOpen	= TestFlag(flag, trunc);
		bool isRead			= TestFlag(flag, read);
		bool isWrite		= TestFlag(flag, write);
		
		mHandle = 0;

		if(isRead || isWrite) {
			if(ensureCreated) {
				FILE* f = fopen(filename, "a+b"); //probably not efficient to open/close file...
				if(f) {
					fclose(f);
				} else {
					return false;
				}
			}

			const char* mode;
			if(isWrite) {
				if(truncAtOpen) {
					mode = "wb";
				} else {
					mode = "r+b";
				}
			} else { //isRead
				GLFi_ASSERT(truncAtOpen == false); //makes no sense !!
				mode = "rb";
			}
		
			mHandle = fopen(filename, mode);

			if(mHandle) {
				fseek(mHandle, 0, SEEK_END);
				mFileStream.mFilePosition.SetFileSize(ftell(mHandle));

				if(!openAtEnd) {
					fseek(mHandle, 0, SEEK_SET);
				}
			}
		}

		return mHandle != 0;
	}


	void Close() {
		if(mHandle) {
			fclose(mHandle);
			mHandle = 0;
		}

		//IOStream::Close();
	}

	size_t GetSize() { 
		return mFileStream.GetSize();
	}

	size_t ReadWithOffset(void* buffer, size_t length, size_t offset) {
		size_t remaining = GetSize() - offset;
		
		length = Min(remaining, length);

		int result = pread(fileno(mHandle), buffer, length, offset);
		
		if(result < 0) {
			int error = errno;
			glf::Console::Print("ReadWithOffset error: %d\n", error);
		}
		
		return result;
	}

	size_t Read(void* buffer, size_t length)  {
		size_t remaining = GetSize() - Tell();
		
		length = Min(remaining, length);
		
		size_t read = fread(buffer, 1, length, mHandle);

		return read;
	}

	size_t Write(const void* buffer, size_t size) {
		return fwrite(buffer, 1, size, mHandle);
	}

	bool Seek(int offset, seek origin) {
		int val = fseek(mHandle, offset, origin);
		return val == 0;
	}
	
	size_t Tell()  const {
		return ftell(mHandle);
	}
};


} //namespace glf


